/*
 * (C) Copyright 2012 Compal Electronics, Inc. 
 *
 * This software is the property of Compal Electronics, Inc.
 * You have to accept the terms in the license file before use.
 *
 */

#ifndef BASE_DATA_H
#define BASE_DATA_H

#include <cstdio>
#include <cstring>

#ifdef ANDROID
#include <android/log.h>
#endif

#ifndef LOG_TAG
#define LOG_TAG "[Facial Engine]"
#endif

#ifndef _DEBUG_OUTPUT_
#define _DEBUG_OUTPUT_ true 
#endif

#ifdef ANDROID
#define cdebug(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define edebug(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#else
#define cdebug(...) do {if(_DEBUG_OUTPUT_) {fprintf(stdout, "(%s)\t", LOG_TAG); fprintf(stdout, __VA_ARGS__);}} while(0)
#define edebug(...) do {fprintf(stderr, "(%s)\t", LOG_TAG); fprintf(stderr, __VA_ARGS__);} while(0)
#endif

namespace facial_compal {


enum {
    MSG_LEFT_EYE_DETECT = 0,
    MSG_RIGHT_EYE_DETECT, 
    MSG_EYES_DETECT,
    MSG_NOSE_DETECT,
    MSG_MOUTH_DETECT,
    MSG_FACE_DETECT,
    MSG_GRAY_IMG,
    MSG_2BIT_IMG,
    MSG_HISTOGRAM,
    MSG_SMILE_DETECT,
    MSG_ADDING_PEOPLE_ERROR, //10
    MSG_ADDING_PEOPLE_SUCCESS, //11
    MSG_UPDATE_BEGIN,   //12
    MSG_UPDATE_END,     //13
    MSG_RECOGNIZE_RESULT, //14
    MSG_ADDING_PEOPLE_MULTI, //15
    MSG_ADDING_PEOPLE_DUPLICATE, //16, add this interface to notify that the uri&&filename pair has added in the past
    MSG_EYES_CLOSURE,
    MSG_EYE_ANGLES,
    MSG_DISTANCE_TO_DB,
};

enum COMPAL_BITMAP_FORMAT {
    COMPAL_BITMAP_FORMAT_YUV422 = 0,
    COMPAL_BITMAP_FORMAT_YUV420,
    COMPAL_BITMAP_FORMAT_RGB565,
    COMPAL_BITMAP_FORMAT_RGB888,
    COMPAL_BITMAP_FORMAT_BGRA8888,
    COMPAL_BITMAP_FORMAT_JPEG,
    COMPAL_BITMAP_FORMAT_NONE,
};

/**
 * The definition of the parameters
 */
class ParametersCompal {
public:
	const char *haarAbsoluteDirectory;	
};

/**
 * The defintion of the rectangle
 */
class RectangleCompal {
public:
    /**
     * Initilize the rectangle
     */
		inline RectangleCompal():fX(0.0f),
		    fY(0.0f), fWidth(0.0f), fHeight(0.0f) {
		} inline RectangleCompal(float x, float y, float width,
					 float height):fX(x), fY(y),
		    fWidth(width), fHeight(height) {

		} inline RectangleCompal(const RectangleCompal & rect) {
			fX = rect.fX;
			fY = rect.fY;
			fWidth = rect.fWidth;
			fHeight = rect.fHeight;
		}

		inline bool isEmpty() const {
			return !((fX < (fX + fWidth)) && (fY < (fY + fHeight)));
		} inline ~ RectangleCompal() {
			clear();
		}

		inline void clear() {
			fX = fY = fWidth = fHeight = 0.0f;
		}

		inline float getX() const {
			return fX;
		} inline float getY() const {
			return fY;
		} inline float getWidth() const {
			return fWidth;
		} inline float getHeight() const {
			return fHeight;
		} inline void dump() const {
			cdebug("Rect[x=%f y=%f width=%f height=%f]\n", fX, fY,
			       fWidth, fHeight);
 		}
private:
		float fX;
		float fY;
		float fWidth;
		float fHeight;
};

class BitmapCompal {
public:
		char *pBuffer;
		int iWidth;
		int iHeight;
		int iFormat;
		unsigned int uSize;
private:
        bool heap;

public:

		inline BitmapCompal() {
			pBuffer = NULL;
			iWidth = 0;
			iHeight = 0;
			iFormat = 0;
			uSize = 0;
            heap = false;
		} 
		inline BitmapCompal(char *buffer, int width, int height,
				      int format, unsigned int size) {
			pBuffer = buffer;
			iWidth = width;
			iHeight = height;
			iFormat = format;
			uSize = size;
            heap = false;
		}

		inline ~ BitmapCompal() {
			iWidth = 0;
			iHeight = 0;
			iFormat = 0;
			uSize = 0;
            if(heap) {
                delete pBuffer;
            } else {
                pBuffer = NULL;
            }
		}

        inline bool convert_2_bgra8888() {
            bool ret = false;
            int *bgra8888 = NULL;
            if(iFormat == COMPAL_BITMAP_FORMAT_YUV420 ) {
                
                bgra8888 = new int[iWidth * iHeight];
                memset(bgra8888, 0, iWidth * iHeight * sizeof(int));

                const int sz = iWidth * iHeight;

                int i, j;
                int Y, Cr = 0, Cb = 0;
                for (j = 0; j < iHeight; j++) {
                    int pixPtr = j * iWidth;
                    const int jDiv2 = j >> 1;
                    for (i = 0; i < iWidth; i++) {
                        Y = pBuffer[pixPtr];
                        if (Y < 0)
                            Y += 255;
                        if ((i & 0x1) != 1) {
                            const int cOff =
                                sz + jDiv2 * iWidth + (i >> 1) * 2;
                            Cb = pBuffer[cOff];
                            if (Cb < 0)
                                Cb += 127;
                            else
                                Cb -= 128;
                            Cr = pBuffer[cOff + 1];
                            if (Cr < 0)
                                Cr += 127;
                            else
                                Cr -= 128;
                        }
                        int R =
                            Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5);
                        if (R < 0)
                            R = 0;
                        else if (R > 255)
                            R = 255;
                        int G =
                            Y - ((Cb >> 2) + (Cb >> 4) + (Cb >> 5)) -
                            ((Cr >> 1)
                             + (Cr >> 3) + (Cr >> 4) + (Cr >> 5));
                                            if (G < 0)
                            G = 0;
                        else if (G > 255)
                            G = 255;
                        int B =
                            Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6);
                        if (B < 0)
                            B = 0;
                        else if (B > 255)
                            B = 255;
                        bgra8888[pixPtr++] =
                            0xff000000 + (B << 16) + (G << 8) + R;
                    }
                }
                if(heap) {
                    delete pBuffer;
                }
                pBuffer = (char *) bgra8888;

                heap = true;
                ret = true;
                iFormat = COMPAL_BITMAP_FORMAT_BGRA8888;
            
            } else {
                return ret;
            }
            return ret;
        }

        inline bool convert_format(enum COMPAL_BITMAP_FORMAT dest) {

            if(iFormat == dest) {
                return true;
            }

            if(COMPAL_BITMAP_FORMAT_BGRA8888 == dest) {
                return convert_2_bgra8888();
            }


            return false;
        }
	};

class SizeCompal {
    public:
        inline SizeCompal(int w = 0, int h = 0) {cdebug("%s: w=%d, h=%d\n", __func__, w, h); width = w; height = h;}
        inline SizeCompal(SizeCompal &sz) {width = sz.width; height = sz.height;}
        int width, height;
    };

enum {
	SYSTEM_TIME_REALTIME = 0,  // system-wide realtime clock
	SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
	SYSTEM_TIME_PROCESS = 2,   // high-resolution per-process clock
	SYSTEM_TIME_THREAD = 3     // high-resolution per-thread clock
};

/**
 * The defintion on Facial feature to select the correct xml file
 */
typedef enum {
	FACE_LEFT_EYE = 0,
	FACE_RIGHT_EYE,
	FACE_EYES,
	FACE_NOSE,
	FACE_MOUTH,
	FACE_FACE,
	FACE_SMILE,
	FACE_EYES_CLOSURE,
	FACE_NONE,
} FaceFeature;

/**
 * Enum the library which we may use
 */
enum {
	COMPAL_OPENCV = 0,
	COMPAL_NVIDIA,
	COMPAL_NEVEN,
	COMPAL_MCA,
	COMPAL_NONE,
};

}				// facial_compal end
#endif
